//记录Promise的三种状态
const PENDING = 'pending'
const FULLFILLED = 'fullfilled'
const REJECTED = 'rejected'

/**
 * 运行一个微队列任务
 * 把传递的函数放到微队列中
 * @param {Function} callback 
 */
function runMicroTask(callback){
    // 判断node环境
    if(typeof process != 'undefined' && process.nextTick){//node环境的process.nextTick就是一个微队列函数
        process.nextTick(callback)
    }else if(MutationObserver){//浏览器环境
        const p = document.createElement('p');
        const observer = new MutationObserver(callback);
        observer.observe(p,{
            childList:true,
        })
        p.innerHTML = '1';
    }
}

/**
 * 判断一个数据是不是Promise对象
 * @param {*} obj 
 * @returns 
 */
function isPromise(obj){
    return !!(obj && typeof obj ==='object' && typeof obj.then === 'function')
}
class MyPromise{

   /**
    * 创建一个Promise
    * @param {Function} executor 任务执行器，立即执行
    */ 
   constructor(executor){
    this._state = PENDING
    this._value = undefined
    this._handlers = []
    try{
        executor(this._resolve.bind(this),this._reject.bind(this))
    }catch(error){
        this._reject(error)
    }
    
   }

   /**
    * 向处理队列中添加一个函数
    * @param {Function} executor 添加的函数
    * @param {String} state 该函数什么状态下执行
    * @param {Function} resolve 让then函数返回的promise成功
    * @param {Function} reject 让then函数返回的promise失败
    */
   _pushHandler(executor,state,resolve,reject){
    this._handlers.push({
        executor,state,resolve,reject
    })
   }

   /**
    * 根据实际情况，执行队列
    * @returns 
    */
   _runHandlers(){
    if(this._state === PENDING){
        //目前任务仍在挂起
        return
    }
    while(this._handlers[0]){//保证每个函数只运行一次，不会执行多次
        const handler = this._handlers[0];
        this._runOneHandler(handler);
        this._handlers.shift();
    }
   }

   /**
    * 处理一个handler
    * @param {Object} handler 
    */
   _runOneHandler({executor,state,resolve,reject}){
    runMicroTask(()=>{
        if(this._state!==state){
            //状态不一致，不处理
            return
        }
        if(typeof executor !=='function'){//传递后续处理并非一个函数，那么穿透
            this._state === FULLFILLED
            ?resolve(this._value)
            :reject(this._value)
            return;
        }
        try{
            const result = executor(this._value)
            if(isPromise(result)){
                result.then(resolve,reject)//如果返回值是一个Promise,那么让then函数返回的promise和这个promise一致
            }else{
                resolve(result)
            }
            
        }
        catch(error){//如果后续处理函数抛出异常，那么让then函数返回的promise失败
            handler.reject(error)
        }
    })
   }
   /**
    * 
    * @param {String} newState 新状态
    * @param {*} value 相关数据
    */
   _changeState(newState,value){
    if(this._state!==PENDING){
        //目前状态已更改
        return
    }
    this._state = newState;
    this._value = value
    this._runHandlers();//状态变化，执行队列
   }
   /**
    * 标记当前任务完成
    * @param {any} data 任务完成的相关数据
    */
   _resolve(data){
    //改变状态和数据
    this._changeState(FULLFILLED,data);
   }
   /**
    * 标记当前任务失败
    * @param {any} reason 任务失败的相关数据
    */
   _reject(reason){
    //改变状态和数据
    this._changeState(REJECTED,reason);
   }
   /**
    * PromiseA+规范的then函数
    * @param {Function} onFullFilled 
    * @param {Function} onRejected 
    */
   then(onFullFilled,onRejected){//1.注册任务
    
    return new MyPromise((resolve,rejected)=>{
        this._pushHandler(onFullFilled,FULLFILLED,resolve,rejected)
        this._pushHandler(onRejected,REJECTED,resolve,rejected)
        this._runHandlers();//有的promise是立即resolve的，这时候then还没有注册呢，所以在这里也写上
    })  
   }

}
// const  p1 = new MyPromise((resolve,reject)=>{
//     resolve(1)
// })
// const p2 = p1.then((data)=>{
//     console.log(data)
//     return new Promise((resolve,reject)=>{
//         resolve(2)
//     })
// }).then((data)=>{
//     console.log(data)
// })
// setTimeout(() => {
//     console.log(p1)
//     console.log(p2)
// }, 2000);

function delay(duration){
    return new MyPromise((resolve,reject)=>{
        setTimeout(() => {
            resolve()
        }, duration);
    })
}

(async function(){
    console.log('stat')
    await delay(1000)
    console.log('end')
})();